

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import java.util.logging.Logger;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

/**
 * A test class to test dynamic compilation API.
 *
 */
public class CompilerAPI {

    private static final Logger logger = Logger.getLogger(CompilerAPI.class.getName());

    /* Instantiating the java compiler */
    private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

    private static DiagnosticCollector<JavaFileObject> diagnostics;

    private static String className;

    

    public static JavaFileManager doMemoryCompilation(String name, String sourceCode) throws Exception {
    	className=name;
        JavaFileManager mFileManager = new MemoryJavaFileManager(compiler.getStandardFileManager(null, Locale.getDefault(), null));

        String[] compileOptions = new String[0];
        Iterable<String> compilationOptions = Arrays.asList(compileOptions);

        boolean status = doCompilation(sourceCode, mFileManager, compilationOptions);
        if (!status) {// If compilation error occurs
			/* Iterate through each compilation problem and print it */
            for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
                System.out.format("Error on line %d in %s",
                        diagnostic.getLineNumber(), diagnostic);
            }
        } 
        
        return mFileManager;
    }

    /**
     * Does the required object initialization and compilation.
     *
     * @throws Exception
     */
    private static boolean doCompilation(String sourceCode, JavaFileManager stdFileManager, Iterable<String> compilationOptions) throws Exception {
        SimpleJavaFileObject fileObject = new DynamicJavaSourceCodeObject(
                className, sourceCode);
        JavaFileObject[] javaFileObjects = new JavaFileObject[]{fileObject};

        /* Create a diagnostic controller, which holds the compilation problems */
        diagnostics = new DiagnosticCollector<JavaFileObject>();

        /*
         * Prepare a list of compilation units (java source code file objects)
         * to input to compilation task
         */
        Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(javaFileObjects);

        /*
         * Create a compilation task from compiler by passing in the required
         * input objects prepared above
         */
        CompilationTask compilerTask = compiler.getTask(null, stdFileManager,
                diagnostics, compilationOptions, null, compilationUnits);

        stdFileManager.close();// Close the file manager

        // Perform the compilation by calling the call method on compilerTask
        // object.
        return compilerTask.call();
    }

   

    public static int executeClassFromMemory(JavaFileManager mFileManager, ArrayList<Integer> _args) throws Exception {
        ClassLoader loader = ((MemoryJavaFileManager)mFileManager).getClassLoader();

	Class<?> clazz = Class.forName(className, true, loader);
	Constructor<?> constructor=clazz.getConstructor(null);
    Object o=constructor.newInstance(null);
	Method m = clazz.getMethod("f", ArrayList.class );
	return (Integer) m.invoke(o, _args);
    }
}
